package com.zc.RecordDemo;

import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.Environment;
import android.os.Handler;
import android.text.format.Time;
import android.util.Log;

import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 7/1/14  11:00 AM
 * Created by JustinZhang.
 */
public class Mp3AudioRecorder {

    private static final String TAG = "MyAudioRecorder";
    private AudioRecord mRecorder = null;
    //private MediaPlayer mPlayer = null;

    public static final int SAMPLE_RATE = 16000;

    private Mp3Conveter mConveter;
    private short[] mBuffer;
    private boolean mIsRecording = false;
    private File mRawFile;
    private File mEncodedFile;

    private OnRecordListener onRecordListener;
    private Handler mHandler;

    public Mp3AudioRecorder() {
        mHandler = new Handler();
    }

    public Mp3AudioRecorder(OnRecordListener onRecordListener) {
        this.onRecordListener = onRecordListener;
        mHandler = new Handler();
    }


    /**
     *
     */
    public interface OnRecordListener {
        /**
         * 开始录音
         */
        void onRecordBegin();

        /**
         * 录音过程中获取音量
         *
         * @param volume
         */
        void onMp3VolumeCallback(int volume);

        /**
         * 录音暂停
         */
        void onRecordPause();

        /**
         * 重新录音
         */
        void onRecordResume();

        /**
         * 录音结束，录音完后开始将.raw转换成.mp3
         */
        void onConvertBegin();

        /**
         * 将.raw转换成.mp3完毕
         */
        void onConvertFinish(String path);
    }

    public void prepare() {
        int bufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO,
                AudioFormat.ENCODING_PCM_16BIT);
        mBuffer = new short[bufferSize];
        mRecorder = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO,
                AudioFormat.ENCODING_PCM_16BIT, bufferSize);
        mConveter = new Mp3Conveter();
    }

    /**
     * 开始录音
     */
    public void startRecording() {
        if (mIsRecording) {
            return;
        }

        Log.e(TAG, "startRcording");
        if (mRecorder == null) {
            Log.e(TAG, "mRocorder is nul this should not happen");
            return;
        }
        mIsRecording = true;
        if (onRecordListener != null) {
            onRecordListener.onRecordBegin();
        }
        mRecorder.startRecording();
        mRawFile = getFile("raw");
        startBufferedWrite(mRawFile);
    }

    private void startBufferedWrite(final File file) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                DataOutputStream output = null;
                try {
                    output = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
                    while (mIsRecording) {
                        if (mIsPause) {
                            continue;
                        }

                        int readSize = mRecorder.read(mBuffer, 0, mBuffer.length);
                        for (int i = 0; i < readSize; i++) {
                            output.writeShort(mBuffer[i]);
                            if (!mIsPause) {
                                //计算音量
                                calculateRealVolume(mBuffer, readSize);
                            }
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    if (output != null) {
                        try {
                            output.flush();
                        } catch (IOException e) {
                            e.printStackTrace();
                        } finally {
                            try {
                                output.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }

            /**
             * 此计算方法来自samsung开发范例
             *
             * @param buffer buffer
             * @param readSize readSize
             */
            private void calculateRealVolume(short[] buffer, int readSize) {
                double sum = 0;
                for (int i = 0; i < readSize; i++) {
                    // 这里没有做运算的优化，为了更加清晰的展示代码
                    sum += buffer[i] * buffer[i];
                }
                if (readSize > 0) {
                    double amplitude = sum / readSize;
                    mVolume = (int) Math.sqrt(amplitude);
                    if (onRecordListener != null) {
                        onRecordListener.onMp3VolumeCallback(mVolume);
                    }
                }
            }
        }).start();
    }

    private int mVolume;

    /**
     * 获取真实的音量。 [算法来自三星]
     *
     * @return 真实音量
     */
    public int getRealVolume() {
        return mVolume;
    }

    /**
     * 获取相对音量。 超过最大值时取最大值。
     *
     * @return 音量
     */
    public int getVolume() {
        if (mVolume >= MAX_VOLUME) {
            return MAX_VOLUME;
        }
        return mVolume;
    }

    /**
     * 对于音量的最大值设置为了4000，而我实际测验中发现大部分声音不超过2000，所以就在代码中暂时设置为2000。
     */
    private static final int MAX_VOLUME = 2000;

    /**
     * 根据资料假定的最大值。 实测时有时超过此值。
     *
     * @return 最大音量值。
     */
    public int getMaxVolume() {
        return MAX_VOLUME;
    }

    private boolean mIsPause = false;

    public void pauseRecording() {
        mIsPause = true;
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (onRecordListener != null) {
                    onRecordListener.onRecordPause();
                }
            }
        }, 100);
    }

    public void restartRecording() {
        mIsPause = false;
        if (onRecordListener != null) {
            onRecordListener.onRecordResume();
        }
    }


    public void stopRecording() {
        Log.e(TAG, "stopRecording");
        if (mRecorder == null) {
            return;
        }
        if (!mIsRecording) {
            return;
        }
        mRecorder.stop();
        mIsPause = false;
        mIsRecording = false;
        mEncodedFile = getFile("mp3");
        //
        if (onRecordListener != null) {
            onRecordListener.onConvertBegin();
        }
        //mConveter.encodeFile(mRawFile.getAbsolutePath(), mEncodedFile.getAbsolutePath());
        //Skipped 57 frames!  The application may be doing too much work on its main thread.
        new Thread(new Runnable() {
            @Override
            public void run() {
                mConveter.encodeFile(mRawFile.getAbsolutePath(), mEncodedFile.getAbsolutePath());
                //mConveter.encodeFile("/storage/emulated/0/bluetooth/test4.amr", mEncodedFile.getAbsolutePath());
                if (onRecordListener != null) {
                    onRecordListener.onConvertFinish(mEncodedFile.getAbsolutePath());
                }
            }
        }).start();
    }


    /*public void startPlaying() {
        Log.e(TAG, "startPlayingstartPlaying");
        if (mPlayer != null) {
            return;
        }
        mPlayer = new MediaPlayer();
        try {
            Log.e("DDD", "DATA SOURCE: " + mEncodedFile.getAbsolutePath());
            mPlayer.setDataSource(mEncodedFile.getAbsolutePath());
            mPlayer.prepare();
            mPlayer.start();
            mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer mp) {
                    mPlayer.release();
                    mPlayer = null;
                }
            });
        } catch (IOException e) {
            Log.e(TAG, e.toString() + "\nprepare() failed");
        }
    }


    public void stopPlaying() {
        Log.e(TAG, "stopPlaying");
        if (mPlayer != null) {
            mPlayer.release();
            mPlayer = null;
        }
    }*/


    public void release() {
      /*  Log.e(TAG, "release");
        if (mPlayer != null) {
            mPlayer.stop();
            mPlayer.release();
            mPlayer = null;
        }*/

        if (mRecorder != null) {
            mRecorder.release();
            mIsPause = false;
            mIsRecording = false;
        }
        mHandler.removeCallbacksAndMessages(null);
        if (mConveter != null)
            mConveter.destroyEncoder();
    }

    private File getFile(final String suffix) {
        Time time = new Time();
        time.setToNow();
        File f = new File(Environment.getExternalStorageDirectory(), time.format("%Y%m%d%H%M%S") + "." + suffix);
        Log.e(TAG, "file address:" + f.getAbsolutePath());
        return f;
    }
}
